home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / xinetd / sio.1.5.6 / siosup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-09  |  23.0 KB  |  1,077 lines

  1. /*
  2.  * (c) Copyright 1992 by Panagiotis Tsirigotis
  3.  * All rights reserved.  The file named COPYRIGHT specifies the terms 
  4.  * and conditions for redistribution.
  5.  */
  6.  
  7. static char RCSid[] = "$Id: siosup.c,v 7.6 1992/12/10 06:40:22 panos Exp $" ;
  8.  
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <fcntl.h>
  12.  
  13. #include "impl.h"
  14. #include "sio.h"
  15.  
  16. #ifdef EVENTS
  17. #include "events.h"
  18. #endif
  19.  
  20. char *malloc() ;
  21. char *realloc() ;
  22.  
  23.  
  24. static __sio_descriptor_t static_descriptor_array[ N_SIO_DESCRIPTORS ] ;
  25. static int n_descriptors = N_SIO_DESCRIPTORS ;
  26. __sio_descriptor_t *__sio_descriptors = static_descriptor_array ;
  27.  
  28. #ifdef EVENTS
  29. static events_s static___sio_events[ N_SIO_DESCRIPTORS ] ;
  30. events_s *__sio_events = static___sio_events ;
  31. #endif
  32.  
  33.  
  34. /*
  35.  * Code for finalization
  36.  */
  37. #ifdef HAS_FINALIZATION_FUNCTION
  38. static int finalizer_installed ;
  39.  
  40. SIO_DEFINE_FIN( sio_cleanup )
  41. {
  42.    (void) Sflush( SIO_FLUSH_ALL ) ;
  43. }
  44. #endif /* HAS_FINALIZATION_FUNCTION */
  45.  
  46.  
  47.  
  48. #ifdef MEMORY_MAP
  49.  
  50. #define CHAR_NULL                ((char *)0)
  51.  
  52. /*
  53.  * PAGES_MAPPED gives the size of each map unit in pages
  54.  */
  55. #define PAGES_MAPPED                2
  56.  
  57. static size_t map_unit_size = 0 ;            /* bytes */
  58. static size_t page_size = 0 ;                    /* bytes */
  59.  
  60. static mapd_s static_mapd_array[ N_SIO_DESCRIPTORS ] ;
  61. static mapd_s *mmap_descriptors = static_mapd_array ;
  62.  
  63. #define MDP( fd )                ( mmap_descriptors + (fd) )
  64.  
  65.  
  66. /*
  67.  * NOTES ON MEMORY MAPPING:
  68.  *
  69.  *     1. Memory mapping works only for file descriptors opened for input
  70.  *        2. Mapping an object to a part of the address space where another
  71.  *            object is mapped will cause the old mapping to disappear (i.e. mmap
  72.  *            will not fail)
  73.  *
  74.  * Memory mapping interface:
  75.  *        SIO_MMAP : maps a file into a portion of the address space.
  76.  *        SIO_MUNMAP: unmap a portion of the address space
  77.  *        SIO_MNEED: indicate to the OS that we will need a portion of
  78.  *                         our address space.
  79.  *
  80.  * The map_unit_size variable defines how much of the file is mapped at
  81.  * a time. It is a multiple of the operating system page size. It is
  82.  * not less than SIO_BUFFER_SIZE unless SIO_BUFFER_SIZE is not a
  83.  * multiple of the page size (so the SIO_BUFFER_SIZE overrides
  84.  * PAGES_MAPPED).
  85.  *
  86.  * NOTE: All memory mapping code is in this file only
  87.  */
  88.  
  89.  
  90. /*
  91.  * Macros used by the memory mapping code
  92.  */
  93. #define FIRST_TIME( dp )                    ( dp->buf == NULL )
  94. #define FATAL_ERROR( msg )                    perror( msg ), exit( 1 )
  95.  
  96. /*
  97.  * Functions to support memory mapping:
  98.  *
  99.  *            try_memory_mapping
  100.  *            buffer_setup
  101.  *            __sio_switch
  102.  *            initial_map
  103.  *            map_unit
  104.  */
  105.  
  106. /*
  107.  * try_memory_mapping attempts to setup the specified descriptor
  108.  * for memory mapping. 
  109.  * It returns FAILURE if it fails and SUCCESS if it is successful.
  110.  * If MEMORY_MAP is not defined, the function is defined to be FAILURE.
  111.  *
  112.  * Sets fields:
  113.  *        memory_mapped:             TRUE or FALSE
  114.  *        
  115.  * Also sets the following fields if memory_mapped is TRUE:
  116.  *    file_offset, file_size, buffer_size
  117.  *
  118.  */
  119. PRIVATE status_e try_memory_mapping( fd, idp, stp )
  120.     int fd ;
  121.     register __sio_id_t *idp ;
  122.     struct stat *stp ;
  123. {
  124.     int access ;
  125.  
  126. #ifdef EVENTS
  127.     EVENT( fd, EV_TRY_MEMORY_MAPPING ) ;
  128. #endif
  129.  
  130.     /*
  131.      * Do not try memory mapping if:
  132.      *        1) The file is not a regular file
  133.      *        2) The file is a regular file but has zero-length
  134.      *        3) The file pointer is not positioned at the beginning of the file
  135.      *        4) The fcntl to obtain the file descriptor flags fails
  136.      *        5) The access mode is not O_RDONLY or O_RDWR
  137.      *
  138.      * The operations are done in this order to avoid the system calls
  139.      * if possible.
  140.      */
  141.     if ( ( ( stp->st_mode & S_IFMT ) != S_IFREG ) ||
  142.           ( stp->st_size == 0 ) ||
  143.           ( lseek( fd, (long)0, 1 ) != 0 ) ||
  144.           ( ( access = fcntl( fd, F_GETFL, 0 ) ) == -1 ) ||
  145.           ( ( access &= 0x3 ) != O_RDONLY && access != O_RDWR ) )
  146.     {
  147.         idp->memory_mapped = FALSE ;
  148.         return( FAILURE ) ;
  149.     }
  150.  
  151.     /*
  152.      * Determine page_size and map_unit_size.
  153.      * Note that the code works even if PAGES_MAPPED is 0.
  154.      */
  155.     if ( page_size == 0 )
  156.     {
  157.         page_size = getpagesize() ;
  158.         map_unit_size = page_size * PAGES_MAPPED ;
  159.         if ( map_unit_size < SIO_BUFFER_SIZE )
  160.             if ( map_unit_size > 0 && SIO_BUFFER_SIZE % map_unit_size == 0 )
  161.                 map_unit_size = SIO_BUFFER_SIZE ;
  162.             else
  163.                 map_unit_size = page_size ;
  164.     }
  165.     
  166.     MDP(fd)->file_offset = 0 ;
  167.     MDP(fd)->file_size = stp->st_size ;
  168.     idp->buffer_size = map_unit_size ;
  169.     idp->buf = CHAR_NULL ;
  170.     idp->memory_mapped = TRUE ;
  171.  
  172.     return( SUCCESS ) ;
  173. }
  174.  
  175.  
  176. /*
  177.  * Copy the current_unit to the primary buffer
  178.  *
  179.  * Sets fields: start, end, nextb
  180.  * Also sets the file pointer
  181.  */
  182. PRIVATE void buffer_setup( idp, fd, mu_cur, mu_next )
  183.     __sio_id_t *idp ;
  184.     int fd ;
  185.     struct map_unit *mu_cur ;
  186.     struct map_unit *mu_next ;
  187. {
  188.     off_t new_offset ;
  189.  
  190.     sio_memcopy( mu_cur->addr, idp->buf, mu_cur->valid_bytes ) ;
  191.     idp->start = idp->buf ;
  192.     idp->end = idp->buf + mu_cur->valid_bytes ;
  193.     idp->nextb = idp->buf + ( idp->nextb - mu_cur->addr ) ;
  194.  
  195.     if ( mu_next->addr != CHAR_NULL )
  196.         new_offset = MDP(fd)->file_offset - mu_next->valid_bytes ;
  197.     else
  198.         new_offset = MDP(fd)->file_offset ;
  199.     (void) lseek( fd, new_offset, 0 ) ;
  200. }
  201.  
  202.  
  203. /*
  204.  * Switch from memory mapping to buffered I/O
  205.  * If any mapping has occured, then the current unit is
  206.  * copied into the buffer that is allocated.
  207.  * Any data in the next unit is ignored.
  208.  * We rely on idp->buf to identify the current unit (so it
  209.  * better be equal to the address of one of the units).
  210.  *
  211.  * Sets fields:
  212.  *            start, end, nextb
  213.  */
  214. status_e __sio_switch( idp, fd )
  215.     register __sio_id_t *idp ;
  216.     int fd ;
  217. {
  218.     register mapd_s *mdp = MDP( fd ) ;
  219.     struct map_unit *mu_cur, *mu_next ;
  220.     unsigned buffer_size = idp->buffer_size ;
  221.     char *buf_addr = idp->buf ;
  222.     int first_time = FIRST_TIME( idp ) ;
  223.     void buffer_setup() ;
  224.     status_e setup_read_buffer() ;
  225.  
  226. #ifdef EVENTS
  227.     EVENT( fd, EV_SIO_SWITCH ) ;
  228. #endif
  229.  
  230.     /*
  231.      * Initialize stream for buffering
  232.      */
  233.     if ( setup_read_buffer( idp, buffer_size ) == FAILURE )
  234.         return( FAILURE ) ;
  235.  
  236.     if ( ! first_time )
  237.     {
  238.         /*
  239.          * Find current, next unit
  240.          */
  241.         if ( buf_addr == mdp->first_unit.addr )
  242.         {
  243.             mu_cur = &mdp->first_unit ;
  244.             mu_next = &mdp->second_unit ;
  245.         }
  246.         else
  247.         {
  248.             mu_cur = &mdp->second_unit ;
  249.             mu_next = &mdp->first_unit ;
  250.         }
  251.  
  252.         buffer_setup( idp, fd, mu_cur, mu_next ) ;
  253.         /*
  254.          * Destroy all mappings
  255.          */
  256.         (void) SIO_MUNMAP( mu_cur->addr, mu_cur->mapped_bytes ) ;
  257.         if ( mu_next->addr != NULL )
  258.             (void) SIO_MUNMAP( mu_next->addr, mu_next->mapped_bytes ) ;
  259.     }
  260.     else
  261.         idp->start = idp->end = idp->nextb = idp->buf ;
  262.  
  263.     idp->memory_mapped = FALSE ;
  264.     return( SUCCESS ) ;
  265. }
  266.  
  267.  
  268. /*
  269.  * initial_map does the first memory map on the file descriptor.
  270.  * It attempts to map both units.
  271.  * The mapping always starts at file offset 0.
  272.  *
  273.  * SETS FIELDS:
  274.  *            first_unit.*, second_unit.*
  275.  *            file_offset
  276.  *
  277.  * Returns: 
  278.  *            number of bytes mapped in first_unit
  279.  *    or
  280.  *            0 to indicate that mmap failed.
  281.  */
  282. PRIVATE int initial_map( mdp, fd )
  283.     register mapd_s *mdp ;
  284.     int fd ;
  285. {
  286.     register caddr_t addr ;
  287.     register size_t requested_length = 2 * map_unit_size ;
  288.     register size_t mapped_length = MIN( mdp->file_size, requested_length ) ;
  289.     size_t bytes_left ;
  290.     register size_t bytes_in_unit ;
  291.  
  292. #ifdef EVENTS
  293.     EVENT( fd, EV_INITIAL_MAP ) ;
  294. #endif
  295.  
  296.     addr = SIO_MMAP( CHAR_NULL, mapped_length, fd, 0 ) ;
  297.     if ( (int) addr == -1 )
  298.         return( 0 ) ;
  299.  
  300.     SIO_MNEED( addr, mapped_length ) ;
  301.  
  302.     /*
  303.      * Map as much as possible in the first unit
  304.      */
  305.     bytes_in_unit = MIN( mapped_length, map_unit_size ) ;
  306.     mdp->first_unit.addr             = addr ;
  307.     mdp->first_unit.mapped_bytes     = bytes_in_unit ;
  308.     mdp->first_unit.valid_bytes     = bytes_in_unit ;
  309.  
  310.     /*
  311.      * If there is more, map it in the second unit.
  312.      */
  313.     bytes_left = mapped_length - bytes_in_unit ;
  314.     if ( bytes_left > 0 )
  315.     {
  316.         mdp->second_unit.addr             = addr + bytes_in_unit ;
  317.         mdp->second_unit.mapped_bytes = bytes_left ;
  318.         mdp->second_unit.valid_bytes     = bytes_left ;
  319.     }
  320.     else
  321.         mdp->second_unit.addr             = CHAR_NULL ;
  322.  
  323.     mdp->file_offset = mapped_length ;
  324.  
  325.     return( mdp->first_unit.valid_bytes ) ;
  326. }
  327.  
  328.  
  329. /*
  330.  * ALGORITHM:
  331.  *
  332.  *        if ( there are more bytes in the file )
  333.  *        {
  334.  *            map them at the given unit
  335.  *            update offset
  336.  *            issue SIO_MNEED()
  337.  *        }
  338.  *        else
  339.  *            unmap the unit
  340.  */
  341. PRIVATE status_e map_unit( mdp, fd, mup )
  342.     register mapd_s *mdp ;
  343.     int fd ;
  344.     register struct map_unit *mup ;
  345. {
  346.     register size_t bytes_left = mdp->file_size - mdp->file_offset ;
  347.     register size_t bytes_to_map = MIN( bytes_left, map_unit_size ) ;
  348.  
  349. #ifdef EVENTS
  350.     EVENT( fd, EV_MAP_UNIT ) ;
  351. #endif
  352.  
  353.     if ( bytes_to_map > 0 )
  354.     {
  355.         if ( (int) SIO_MMAP( mup->addr, bytes_to_map,
  356.                                                             fd, mdp->file_offset ) == -1 )
  357.             return( FAILURE ) ;            /* XXX: need to do more ? */
  358.         
  359.         mup->valid_bytes = bytes_to_map ;
  360.         ASSERT( mup->valid_bytes <= mup->mapped_bytes ) ;
  361.         mdp->file_offset += bytes_to_map ;
  362.         SIO_MNEED( mup->addr, mup->valid_bytes ) ;
  363.     }
  364.     else
  365.     {
  366.         (void) SIO_MUNMAP( mup->addr, mup->mapped_bytes ) ;
  367.         mup->addr = CHAR_NULL ;
  368.     }
  369.     return( SUCCESS ) ;
  370. }
  371.  
  372. #else
  373.  
  374. #define try_memory_mapping( x, y, z )                FAILURE
  375.  
  376. #endif /* MEMORY_MAP */
  377.  
  378.  
  379. PRIVATE status_e setup_read_buffer( idp, buf_size )
  380.     register __sio_id_t *idp ;
  381.     unsigned buf_size ;
  382. {
  383.     register char *buf ;
  384.  
  385.     /*
  386.      * First allocate space for 2 buffers: primary and auxiliary
  387.      */
  388.     buf = malloc( buf_size * 2 ) ;
  389.     if ( buf == NULL )
  390.         return( FAILURE ) ;
  391.  
  392.     /*
  393.      * The descriptor buf field should point to the start of the main buffer
  394.      */
  395.     idp->buf = buf + buf_size ;
  396.     idp->buffer_size = buf_size ;
  397.     return( SUCCESS ) ;
  398. }
  399.  
  400.  
  401. PRIVATE status_e init_input_stream( idp, fd, stp )
  402.     register __sio_id_t *idp ;
  403.     int fd ;
  404.     struct stat *stp ;
  405. {
  406. #ifdef EVENTS
  407.     EVENT( fd, EV_INIT_INPUT_STREAM ) ;
  408. #endif
  409.  
  410.     /*
  411.      * First initialize the fields relevant to buffering: buf, buffer_size
  412.      */
  413.     if ( try_memory_mapping( fd, idp, stp ) == FAILURE )
  414.     {
  415.         /*
  416.          * Try to use normal buffering
  417.          */
  418.         unsigned buf_size = (unsigned)
  419.                             ( stp->st_blksize ? stp->st_blksize : SIO_BUFFER_SIZE ) ;
  420.         
  421.         if ( setup_read_buffer( idp, buf_size ) == FAILURE )
  422.             return( FAILURE ) ;
  423.     }
  424.  
  425.      /*
  426.      * Initialize remaining descriptor fields
  427.      */
  428.     idp->max_line_length = 2 * idp->buffer_size - 1 ;
  429.     idp->start = idp->end = idp->nextb = idp->buf ;
  430.     idp->tied_fd = SIO_NO_TIED_FD ;
  431.  
  432.     return( SUCCESS ) ;
  433. }
  434.  
  435.  
  436. PRIVATE status_e init_output_stream( odp, fd, stp )
  437.     register __sio_od_t *odp ;
  438.     int fd ;
  439.     struct stat *stp ;
  440. {
  441.     register unsigned buf_size ;
  442.     register char *buf ;
  443.  
  444. #ifdef EVENTS
  445.     EVENT( fd, EV_INIT_OUTPUT_STREAM ) ;
  446. #endif
  447.  
  448.     buf_size = (unsigned)
  449.                         ( stp->st_blksize ? stp->st_blksize : SIO_BUFFER_SIZE ) ;
  450.     buf = malloc( buf_size ) ;
  451.     if ( buf == NULL )
  452.         return( FAILURE ) ;
  453.     
  454.     /*
  455.      * Initialize buffering fields
  456.      */
  457.     odp->buf = buf ;
  458.     odp->buffer_size = buf_size ;
  459.     odp->buf_end = odp->buf + buf_size ;
  460.  
  461.     /*
  462.      * Initialize remaining fields
  463.      */
  464.     odp->start = odp->nextb = odp->buf ;
  465.     if ( isatty( fd ) )
  466.         odp->buftype = SIO_LINEBUF ;
  467.  
  468.     if ( fd == 2 )
  469.         odp->buftype = SIO_NOBUF ;
  470.  
  471.     return( SUCCESS ) ;
  472. }
  473.  
  474.  
  475. #ifndef HAS_ISATTY
  476.  
  477. #ifdef SYSV_TTY
  478.  
  479. #include <termio.h>
  480.  
  481. PRIVATE int isatty( fd )
  482.     int fd ;
  483. {
  484.     struct termio t ;
  485.  
  486.     if ( ioctl( fd, TCGETA, &t ) == -1 && errno == ENOTTY )
  487.         return( FALSE ) ;
  488.     else
  489.         return( TRUE ) ;
  490. }
  491. #endif    /* SYSV_TTY */
  492.  
  493. #ifdef BSD43_TTY
  494.  
  495. #include <sgtty.h>
  496.  
  497. PRIVATE int isatty( fd )
  498.     int fd ;
  499. {
  500.     struct sgttyb s ;
  501.  
  502.     if ( ioctl( fd, TIOCGETP, &s ) == -1 && errno == ENOTTY )
  503.         return( FALSE ) ;
  504.     else
  505.         return( TRUE ) ;
  506. }
  507. #endif    /* BSD43_TTY */
  508.  
  509. #endif    /* ! HAS_ISATTY */
  510.  
  511.  
  512. /*
  513.  * Initialize stream I/O for a file descriptor.
  514.  *
  515.  * Arguments:
  516.  *        fd:                file descriptor
  517.  *        dp:                descriptor pointer
  518.  *        stream_type:     either __SIO_INPUT_STREAM or __SIO_OUTPUT_STREAM
  519.  *
  520.  * Returns
  521.  *        0             if successful
  522.  *      SIO_ERR    if the file descriptor is not valid (sets errno)
  523.  *   exits        if stream_type is not __SIO_INPUT_STREAM or __SIO_OUTPUT_STREAM
  524.  */
  525. int __sio_init( dp, fd, stream_type )
  526.     register __sio_descriptor_t *dp ;
  527.     int fd ;
  528.     enum __sio_stream stream_type ;
  529. {
  530.     struct stat st ;
  531.     void terminate() ;
  532.  
  533. #ifdef EVENTS
  534.     EVENT( fd, EV_SIO_INIT ) ;
  535. #endif
  536.  
  537.     if ( fstat( fd, &st ) == -1 )
  538.         return( SIO_ERR ) ;
  539.  
  540.     switch ( stream_type )
  541.     {
  542.         case __SIO_INPUT_STREAM:
  543.             if ( init_input_stream( IDP( dp ), fd, &st ) == FAILURE )
  544.                 return( SIO_ERR ) ;
  545.             break ;
  546.  
  547.         case __SIO_OUTPUT_STREAM:
  548.             if ( init_output_stream( ODP( dp ), fd, &st ) == FAILURE )
  549.                 return( SIO_ERR ) ;
  550.             break ;
  551.             
  552.         default:
  553.             terminate( "SIO __sio_init: bad stream type (internal error).\n" ) ;
  554.             /* NOTREACHED */
  555.     }
  556.     dp->stream_type = stream_type ;
  557.     dp->initialized = TRUE ;
  558.  
  559. #ifdef HAS_FINALIZATION_FUNCTION
  560.     if ( ! finalizer_installed )
  561.     {
  562.         if ( ! SIO_FINALIZE( sio_cleanup ) )
  563.         {
  564.             char *s = "SIO __sio_init: finalizer installation failed\n" ;
  565.  
  566.             (void) write( 2, s, strlen( s ) ) ;
  567.         }
  568.         else
  569.             finalizer_installed = TRUE ;
  570.     }
  571. #endif /* HAS_FINALIZATION_FUNCTION */
  572.  
  573.     return( 0 ) ;
  574. }
  575.  
  576.  
  577. /*
  578.  * __sio_writef writes the data in the buffer to the file descriptor.
  579.  *
  580.  * It tries to write as much data as possible until either all data
  581.  * are written or an error occurs. EINTR is the only error that is
  582.  * ignored.
  583.  * In case an error occurs but some data were written, that number
  584.  * is returned instead of SIO_ERR.
  585.  *
  586.  * Fields modified:
  587.  *        When successful: start, nextb
  588.  *        When not successful: start
  589.  *
  590.  * Return value:
  591.  *        Number of bytes written
  592.  *        SIO_ERR, if write(2) fails and no data were written
  593.  */ 
  594. int __sio_writef( odp, fd )
  595.     register __sio_od_t *odp ;
  596.     int fd ;
  597. {
  598.     register int b_in_buffer ;
  599.     register int cc_total = 0 ;
  600.  
  601. #ifdef EVENTS
  602.     EVENT( fd, EV_SIO_WRITEF ) ;
  603. #endif
  604.  
  605.     /*
  606.      * Make sure we don't exceed the buffer limits
  607.      *    Maybe we should log this ?            XXX
  608.      */
  609.     if ( odp->nextb > odp->buf_end )
  610.         odp->nextb = odp->buf_end ;
  611.  
  612.     b_in_buffer = odp->nextb - odp->start ;
  613.  
  614.     if ( b_in_buffer == 0 )
  615.         return( 0 ) ;
  616.     
  617.     for ( ;; )
  618.     {
  619.         register int cc ;
  620.  
  621.         cc = write( fd, odp->start, b_in_buffer ) ;
  622.         if ( cc == b_in_buffer )
  623.         {
  624.             odp->start = odp->nextb = odp->buf ;
  625.             cc_total += cc ;
  626.             break ;
  627.         }
  628.         else if ( cc == -1 )
  629.         {
  630.             if ( errno == EINTR )
  631.                 continue ;
  632.             else
  633.                 /*
  634.                  * If some bytes were written, return that number, otherwise
  635.                  * return SIO_ERR
  636.                  */
  637.                 return( ( cc_total != 0 ) ? cc_total : SIO_ERR ) ;
  638.         }
  639.         else            /* some bytes were written */
  640.         {
  641.             odp->start += cc ;            /* advance start of buffer */
  642.             b_in_buffer -= cc ;            /* decrease number bytes left in buffer */
  643.             cc_total += cc ;                /* count the bytes that were written */
  644.         }
  645.     }
  646.     return( cc_total ) ;
  647. }
  648.  
  649.  
  650. /*
  651.  * __sio_readf reads data from the file descriptor into the buffer.
  652.  * Unlike __sio_writef it does NOT try to read as much data as will fit
  653.  * in the buffer. It ignores EINTR.
  654.  *
  655.  * Returns: # of bytes read or SIO_ERR
  656.  *
  657.  * Fields set:
  658.  *         If it does not return SIO_ERR, it sets start, nextb, end
  659.  *            If it returns SIO_ERR, it does not change anything
  660.  */
  661. int __sio_readf( idp, fd )
  662.     register __sio_id_t *idp ;
  663.     int fd ;
  664. {
  665.     register int cc ;
  666.  
  667. #ifdef EVENTS
  668.     EVENT( fd, EV_SIO_READF ) ;
  669. #endif
  670.  
  671.     /*
  672.      * First check for a tied fd and flush the stream if necessary
  673.      *
  674.      *         XXX    the return value of __sio_writef is not checked.
  675.      *                    Is that right ?
  676.      */
  677.     if ( idp->tied_fd != SIO_NO_TIED_FD )
  678.         (void) __sio_writef( &__SIO_OD( idp->tied_fd ), idp->tied_fd ) ;
  679.  
  680. #ifdef MEMORY_MAP
  681.     if ( idp->memory_mapped )
  682.     {
  683.         register mapd_s *mdp = MDP( fd ) ;
  684.  
  685.         /*
  686.          * The functions initial_map and map_unit may fail.
  687.          * In either case, we switch to buffered I/O.
  688.          * If initial_map fails, we have read no data, so we
  689.          * should perform a read(2).
  690.          * If map_unit fails (for the next unit), we still have
  691.          * the data in the current unit, so we can return.
  692.          */
  693.         if ( FIRST_TIME( idp ) )
  694.         {
  695.             cc = initial_map( mdp, fd ) ;
  696.             if ( cc > 0 )
  697.                 idp->buf = mdp->first_unit.addr ;
  698.             else
  699.             {
  700.                 if ( __sio_switch( idp, fd ) == FAILURE )
  701.                     return( SIO_ERR ) ;
  702.                 cc = -1 ;
  703.             }
  704.         }
  705.         else
  706.         {
  707.             register struct map_unit *mu_cur, *mu_next ;
  708.  
  709.             if ( idp->buf == mdp->first_unit.addr )
  710.             {
  711.                 mu_cur = &mdp->first_unit ;
  712.                 mu_next = &mdp->second_unit ;
  713.             }
  714.             else
  715.             {
  716.                 mu_cur = &mdp->second_unit ;
  717.                 mu_next = &mdp->first_unit ;
  718.             }
  719.  
  720.             if ( mu_next->addr != NULL )
  721.             {
  722.                 idp->buf = mu_next->addr ;
  723.                 cc = mu_next->valid_bytes ;
  724.                 /*
  725.                  * XXX:  Here we may return SIO_ERR even though there
  726.                  *           are data in the current unit because the switch
  727.                  *           fails (possibly because malloc failed).
  728.                  */
  729.                 if ( map_unit( mdp, fd, mu_cur ) == FAILURE &&
  730.                                         __sio_switch( idp, fd ) == FAILURE )
  731.                     return( SIO_ERR ) ;
  732.             }
  733.             else
  734.                 cc = 0 ;
  735.         }
  736.         if ( cc >= 0 )
  737.         {
  738.             idp->end = idp->buf + cc ;
  739.             idp->start = idp->nextb = idp->buf ;
  740.             return( cc ) ;
  741.         }
  742.     }
  743. #endif /* MEMORY_MAP */
  744.  
  745.     for ( ;; )
  746.     {
  747.         cc = read( fd, idp->buf, (int) idp->buffer_size ) ;
  748.         if ( cc == -1 )
  749.             if ( errno == EINTR )
  750.                 continue ;
  751.             else
  752.                 return( SIO_ERR ) ;
  753.         else
  754.             break ;
  755.     }
  756.  
  757.     idp->end = idp->buf + cc ;
  758.     idp->start = idp->nextb = idp->buf ;
  759.     return( cc ) ;
  760. }
  761.  
  762.  
  763. /*
  764.  * __sio_extend_buffer is used by Srdline to extend the buffer
  765.  * If successful, it returns the number of bytes that have been read.
  766.  * If it fails (because of end-of-file or I/O error), it returns 0 or -1.
  767.  *
  768.  * Fields modified:
  769.  *     idp->start points to the start of the buffer area (which is in the
  770.  *     auxiliary buffer)
  771.  *        Also, if successful, idp->nextb is set to idp->buf, idp->end is modified.
  772.  */
  773. int __sio_extend_buffer( idp, fd, b_left )
  774.     register __sio_id_t *idp ;
  775.     int fd ;
  776.     register int b_left ;
  777. {
  778.     register int b_read ;
  779.  
  780. #ifdef EVENTS
  781.     EVENT( fd, EV_SIO_EXTEND_BUFFER ) ;
  782. #endif
  783.  
  784.     /*
  785.      * copy to auxiliary buffer
  786.      */
  787.     if ( b_left )
  788.         sio_memcopy( idp->nextb, idp->buf - b_left, b_left ) ;
  789.     b_read = __sio_readf( idp, fd ) ;
  790.     idp->start = idp->buf - b_left ;
  791.     return( b_read ) ;
  792. }
  793.  
  794.  
  795. /*
  796.  * __sio_more tries to read more data from the given file descriptor iff
  797.  * there is free space in the buffer.
  798.  * __sio_more is used only by Srdline and only AFTER __sio_extend_buffer
  799.  * has been called. This implies that 
  800.  *        a) this is not a memory mapped file
  801.  *        b) __sio_readf has been called (so we don't need to check for tied fd's
  802.  *
  803.  * Fields modified (only if successful):
  804.  *            idp->end
  805.  *
  806.  * Return value: the number of bytes read.
  807.  */
  808. int __sio_more( idp, fd )
  809.     register __sio_id_t *idp ;
  810.     int fd ;
  811. {
  812.     register int b_left = &idp->buf[ idp->buffer_size ] - idp->end ;
  813.     register int cc ;
  814.  
  815. #ifdef EVENTS
  816.     EVENT( fd, EV_SIO_MORE ) ;
  817. #endif
  818.  
  819.     if ( b_left <= 0 )
  820.         return( 0 ) ;
  821.     
  822.     for ( ;; )
  823.     {
  824.         cc = read( fd, idp->end, b_left ) ;
  825.         if ( cc >= 0 )
  826.         {
  827.             idp->end += cc ;
  828.             return( cc ) ;
  829.         }
  830.         else
  831.             if ( errno == EINTR )
  832.                 continue ;
  833.             else
  834.                 return( SIO_ERR ) ;
  835.     }
  836. }
  837.  
  838.  
  839. /*
  840.  * Finalize a buffer by unmapping the file or freeing the malloc'ed memory
  841.  */
  842. int Sdone( fd )
  843.     int fd ;
  844. {
  845.     register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
  846.  
  847. #ifdef EVENTS
  848.     EVENT( fd, EV_SDONE ) ;
  849. #endif
  850.  
  851.     if ( ! DESCRIPTOR_INITIALIZED( dp ) )
  852.     {
  853.         errno = EBADF ;
  854.         return( SIO_ERR ) ;
  855.     }
  856.  
  857.     switch ( dp->stream_type )
  858.     {
  859.         case __SIO_INPUT_STREAM:
  860.             {
  861.                 register __sio_id_t *idp = IDP( dp ) ;
  862.  
  863. #ifdef MEMORY_MAP
  864.                 if ( idp->memory_mapped )
  865.                 {
  866.                     register mapd_s *mdp = MDP( fd ) ;
  867.  
  868.                     if ( mdp->first_unit.addr != CHAR_NULL )
  869.                         (void) SIO_MUNMAP( mdp->first_unit.addr,
  870.                                                         mdp->first_unit.mapped_bytes ) ;
  871.                     if ( mdp->second_unit.addr != CHAR_NULL )
  872.                         (void) SIO_MUNMAP( mdp->second_unit.addr,
  873.                                                         mdp->second_unit.mapped_bytes ) ;
  874.                     idp->memory_mapped = FALSE ;
  875.                 }
  876.                 else
  877. #endif    /* MEMORY_MAP */
  878.                     free( idp->buf - idp->buffer_size ) ;
  879.                     idp->nextb = idp->end = NULL ;
  880.             }
  881.             break ;
  882.         
  883.         case __SIO_OUTPUT_STREAM:
  884.             {
  885.                 register __sio_od_t *odp = ODP( dp ) ;
  886.  
  887.                 if ( Sflush( fd ) == SIO_ERR )
  888.                     return( SIO_ERR ) ;
  889.                 free( odp->buf ) ;
  890.                 odp->nextb = odp->buf_end = NULL ;
  891.             }
  892.             break ;
  893.         
  894.         default:
  895.             terminate( "SIO Sdone: bad stream type\n" ) ;
  896.     }
  897.  
  898.     dp->initialized = FALSE ;
  899.     return( 0 ) ;
  900. }
  901.  
  902.  
  903. PRIVATE char *expand( area, old_size, new_size, is_static )
  904.     char *area ;
  905.     unsigned old_size, new_size ;
  906.     int is_static ;
  907. {
  908.     char *new_area ;
  909.  
  910.     if ( is_static )
  911.     {
  912.         if ( ( new_area = malloc( new_size ) ) == NULL )
  913.             return( NULL ) ;
  914.         (void) memcpy( new_area, area, old_size ) ;
  915.     }
  916.     else
  917.         if ( ( new_area = realloc( area, new_size ) ) == NULL )
  918.             return( NULL ) ;
  919.     return( new_area ) ;
  920. }
  921.  
  922.  
  923. #include <sys/time.h>
  924. #include <sys/resource.h>
  925.  
  926. PRIVATE int get_fd_limit()
  927. {
  928. #ifdef RLIMIT_NOFILE
  929.     struct rlimit rl ;
  930.  
  931.     (void) getrlimit( RLIMIT_NOFILE, &rl ) ;
  932.     return( rl.rlim_cur ) ;
  933. #else
  934. #ifdef FIXED_LIMIT
  935.     return( N_SIO_DESCRIPTORS ) :
  936. #else
  937.     return( getdtablesize() ) ;
  938. #endif
  939. #endif
  940. }
  941.  
  942. /*
  943.  * Expand the descriptor array (and if we use memory mapping the
  944.  * memory mapping descriptors). We first expand the memory mapping
  945.  * descriptors.
  946.  * There is no problem if the expansion of the SIO descriptors fails
  947.  * (i.e. there is no need to undo anything).
  948.  */
  949. int Smorefds()
  950. {
  951.     char *p ;
  952.     int is_static ;
  953.     unsigned new_size, old_size ;
  954.     int n_fds = get_fd_limit() ;
  955.  
  956.     if ( n_fds <= n_descriptors )
  957.         return( 0 ) ;
  958.  
  959. #ifdef EVENTS
  960.     old_size = n_descriptors * sizeof( events_s ) ;
  961.     new_size = n_fds * sizeof( events_s ) ;
  962.     is_static = ( __sio_events == static___sio_events ) ;
  963.     p = expand( (char *)__sio_events, old_size, new_size, is_static ) ;
  964.     if ( p == NULL )
  965.         return( SIO_ERR ) ;
  966.     __sio_events = (events_s *) p ;
  967. #endif    /* EVENTS */
  968.  
  969. #ifdef MEMORY_MAP
  970.     old_size = n_descriptors * sizeof( mapd_s ) ;
  971.     new_size = n_fds * sizeof( mapd_s ) ;
  972.     is_static = ( mmap_descriptors == static_mapd_array ) ;
  973.     p = expand( (char *)mmap_descriptors, old_size, new_size, is_static ) ;
  974.     if ( p == NULL )
  975.         return( SIO_ERR ) ;
  976.     mmap_descriptors = (mapd_s *) p ;
  977. #endif    /* MEMORY_MAP */
  978.     
  979.     old_size = n_descriptors * sizeof( __sio_descriptor_t ) ;
  980.     new_size = n_fds * sizeof( __sio_descriptor_t ) ;
  981.     is_static =  ( __sio_descriptors == static_descriptor_array ) ;
  982.     p = expand( (char *)__sio_descriptors, old_size, new_size, is_static ) ;
  983.     if ( p == NULL )
  984.         return( SIO_ERR ) ;
  985.     __sio_descriptors = (__sio_descriptor_t *) p ;
  986.  
  987.     n_descriptors = n_fds ;
  988.     return( 0 ) ;
  989. }
  990.  
  991.  
  992. #ifdef EVENTS
  993.  
  994. int __sio_enable_events( fd )
  995. {
  996.     char *p = malloc( EVENT_ENTRIES * sizeof( short ) ) ;
  997.  
  998.     if ( p == NULL )
  999.         return( SIO_ERR ) ;
  1000.  
  1001.     __sio_events[ fd ].codes = (short *) p ;
  1002.     return( 0 ) ;
  1003. }
  1004.  
  1005.  
  1006. int __sio_get_events( fd, buf, size )
  1007.     int fd ;
  1008.     char *buf ;
  1009.     int size ;
  1010. {
  1011.     events_s *evp = &__sio_events[ fd ] ;
  1012.     int bufentries ;
  1013.     int range1, range2 ;
  1014.     int diff ;
  1015.     char *p ;
  1016.     int cc ;
  1017.     int cc_total ;
  1018.     int move_entries ;
  1019.  
  1020.     if ( evp->codes == NULL )
  1021.         return( 0 ) ;
  1022.     
  1023.     diff = evp->next - evp->start ;
  1024.     if ( diff == 0 )
  1025.         return( 0 ) ;
  1026.  
  1027.     if ( diff > 0 )
  1028.     {
  1029.         range1 = diff ;
  1030.         range2 = 0 ;
  1031.     }
  1032.     else
  1033.     {
  1034.         range1 = EVENT_ENTRIES - evp->start ;
  1035.         range2 = evp->next ;
  1036.     }
  1037.  
  1038.     bufentries = size / sizeof( short ) ;
  1039.     p = buf ;
  1040.     cc_total = 0 ;
  1041.  
  1042.     move_entries = MIN( range1, bufentries ) ;
  1043.     cc = move_entries * sizeof( short ) ;
  1044.     (void) memcpy( p, (char *) &evp->codes[ evp->start ], cc ) ;
  1045.     cc_total += cc ;
  1046.     p += cc ;
  1047.     bufentries -= range1 ;
  1048.     ADD( evp->start, move_entries ) ;
  1049.  
  1050.     if ( bufentries == 0 || range2 == 0 )
  1051.         return( cc_total ) ;
  1052.  
  1053.     move_entries = MIN( range2, bufentries ) ;
  1054.     cc = move_entries * sizeof( short ) ;
  1055.     (void) memcpy( p, (char *) &evp->codes[ evp->start ], cc ) ;
  1056.     cc_total += cc ;
  1057.     ADD( evp->start, move_entries ) ;
  1058.  
  1059.     return( cc_total ) ;
  1060. }
  1061.  
  1062. #endif     /* EVENTS */
  1063.  
  1064.  
  1065. /*
  1066.  * Simple function that prints the string s at stderr and then calls
  1067.  * exit
  1068.  */
  1069. PRIVATE void terminate( s )
  1070.     char *s ;
  1071. {
  1072.     (void) write( 2, s, strlen( s ) ) ;
  1073.     (void) abort() ;
  1074.     exit( 1 ) ;                /* in case abort fails */
  1075. }
  1076.  
  1077.